package com.gin.no_gay_alliance.worker;

import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.work.BackoffPolicy;
import androidx.work.Constraints;
import androidx.work.Data;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.WorkRequest;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

import com.gin.nga.response.body.ReadBody;
import com.gin.no_gay_alliance.app.MyApplication;
import com.gin.no_gay_alliance.database.dao.ScanTaskDao;
import com.gin.no_gay_alliance.database.entity.ScanTask;
import com.gin.no_gay_alliance.database.manager.ReplyHistoryManager;

import java.io.IOException;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

/**
 * 监控扫描工作, 根据一个扫描任务, 扫描其最大页和次大页
 *
 * @author : ginstone
 * @version : v1.0.0
 * @since : 2023/9/21 14:54
 **/
public class WatchingScanWorker extends Worker {
    private static final String TAG = WatchingScanWorker.class.getSimpleName();
    /**
     * 运行参数key： 任务id
     */
    private static final String ARG_ID = "id";
    private final int id;
    private ScanTaskDao dao;

    public WatchingScanWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
        Data inputData = workerParams.getInputData();
        this.id = inputData.getInt(ARG_ID, -1);
    }

    @NonNull
    @Override
    public Result doWork() {
        dao = MyApplication.app.ngaDatabase.scanTaskDao();
        ScanTask scanTask = dao.get(id);
        // 误差
        int offset = 5;
        // 如果当前离上次扫描时间小于5分钟，不执行扫描
        if (now() + offset < scanTask.timestampWatching + TimeUnit.MINUTES.toSeconds(5)) {
            return Result.success();
        }

        Log.d(TAG, String.format(Locale.CHINA, "[监控主题] 扫描开始: %d", scanTask.topicId));

        // 选择本次任务扫描的最大页
        int page = scanTask.pageWatched != 0 ? scanTask.pageWatched : scanTask.totalPage;
        try {
            // 最大页响应
            ReadBody body1 = ScanTaskWorker.scan(scanTask.topicId, page);
            // 次大页响应
            ReadBody body2 = page > 1 ? ScanTaskWorker.scan(scanTask.topicId, page - 1) : null;

            //写入回复历史
            ReplyHistoryManager.addReplyHistories(body1);
            if (body2 != null) {
                ReplyHistoryManager.addReplyHistories(body2);
            }
            // 更新最大页, 时间戳
            ScanTask task = dao.get(id);
            task.totalPage = body1.getTotalPage();
            task.timestampWatching = now();
            // 如果当前最大页大于本次扫描页，下一次扫描页+1
            if (body1.getTotalPage() > page) {
                task.pageWatched = page + 1;
            }
            dao.update(task);

        } catch (IOException e) {
            // 发生异常，失败
            e.printStackTrace();
            return Result.failure();
        }
        Log.d(TAG, String.format(Locale.CHINA, "[监控主题] 扫描完毕: %d", scanTask.topicId));
        return Result.success();
    }

    /**
     * 启动工作
     *
     * @param id 任务id
     */
    public static void startWorker(int id) {
        //创建工作请求
        WorkRequest workRequest = buildWorkRequest(id);
        //提交任务
        WorkManager.getInstance(MyApplication.app).enqueue(workRequest);
    }

    /**
     * 打包运行参数
     *
     * @param id 任务id
     * @return data
     */
    public static Data buildData(int id) {
        Data.Builder builder = new Data.Builder();
        builder.putInt(ARG_ID, id);
        return builder.build();
    }

    /**
     * 创建工作请求
     *
     * @param id 任务id
     * @return 工作请求
     */
    public static WorkRequest buildWorkRequest(int id) {
        // 连上网络才执行
        Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();

        return new OneTimeWorkRequest.Builder(WatchingScanWorker.class).setInputData(buildData(id)).setConstraints(constraints)
                // 重试策略
                .setBackoffCriteria(BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS).build();
    }

    private static long now() {
        return System.currentTimeMillis() / 1000;
    }

}
